package com.acme.serialization;

import com.acme.serialization.impl.JavaObjectSerializer;
import com.acme.serialization.impl.JsonSensorDataObjectSerializer;
import com.acme.serialization.impl.ProtobufSensorDataSerializer;
import com.acme.serialization.impl.XstreamObjectSerializer;
import org.apache.log4j.Logger;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Gregory Sobko
 */
public class SerializationServer {
    private static Logger logger = Logger.getLogger(SerializationServer.class);

    public static final int PORT = 12346;
    public static void main(String[] args) throws SerializationException, IOException {
        final Map<String, ObjectSerializer<SensorData[]>> protocolMap = getProtocolSerializers();
        while (true){
            logger.info("Awaiting client connection");
            try(ServerSocket serverSocket = new ServerSocket(PORT);
                Socket socket = serverSocket.accept();
                PrintWriter clientWriter = new PrintWriter(socket.getOutputStream(), true);
                InputStream clientDataStream = socket.getInputStream();
                BufferedReader clientReader = new BufferedReader(new InputStreamReader(socket.getInputStream()))){
                logger.info("Client accepted");
                String protocol = clientReader.readLine();
                logger.info("trying to use protocol " + protocol);
                if (protocolMap.containsKey(protocol)) {
                    ObjectSerializer <SensorData[]> objectSerializer = protocolMap.get(protocol);
                    clientWriter.println("Using protocol " + protocol + " ...");
                    logger.info("Using protocol " + protocol + " ...! Receiving data from client...");
                    SensorData[] sensorDatas = objectSerializer.deserialize(clientDataStream);
                    logger.info("Received batch from client with length: " + sensorDatas.length);
                    double avg = 0;
                    for (SensorData sensorData : sensorDatas) {
                        avg += sensorData.getTemperature();
                    }
                    avg /= sensorDatas.length;
                    logger.info("Average temperature = " + avg);
                } else {
                    clientWriter.println("Protocol " + protocol + " is not supported!");
                    logger.error("Protocol " + protocol + " is not supported!");
                }
                clientWriter.println("Server responded ok!");
            } catch (Exception e){
                logger.error(e);
            }
            System.gc();
        }
    }

    public static Map<String, ObjectSerializer<SensorData[]>> getProtocolSerializers(){
        ObjectSerializer<SensorData[]> objectSerializer1 = new JavaObjectSerializer<>();
        ObjectSerializer<SensorData[]> objectSerializer2 = new JsonSensorDataObjectSerializer();
        ObjectSerializer<SensorData[]> objectSerializer3 = new ProtobufSensorDataSerializer();
        ObjectSerializer<SensorData[]> objectSerializer4 = new XstreamObjectSerializer<>();
        Map<String, ObjectSerializer<SensorData[]>> objectSerializerMap = new HashMap<>();
        objectSerializerMap.put(objectSerializer1.getProtocolName(), objectSerializer1);
        objectSerializerMap.put(objectSerializer2.getProtocolName(), objectSerializer2);
        objectSerializerMap.put(objectSerializer3.getProtocolName(), objectSerializer3);
        objectSerializerMap.put(objectSerializer4.getProtocolName(), objectSerializer4);
        return Collections.unmodifiableMap(objectSerializerMap);

    }
}
